#include"threadpool.h"

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#include<cassert>
#include<sys/epoll.h>
#include <sys/mman.h>
#include <stdarg.h>

int epollfd;
char* httphead = "GET /http/index.html HTTP/1.1\r\nHost: 192.168.42.128:8080\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\nConnection: keep-alive\r\n\r\n";

threadpool* th;

int setnonblocking(int fd)
{
    int old_option=fcntl(fd,F_GETFL);
    int new_option=old_option | O_NONBLOCK;
    fcntl(fd,F_SETFL,new_option);
    return old_option;
}

void addfd(int epollfd,int fd,bool one_shot)
{
    epoll_event event;
    event.data.fd=fd;
    event.events=EPOLLIN|EPOLLET|EPOLLRDHUP;
    if(one_shot)
        event.events|=EPOLLONESHOT;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
    setnonblocking(fd);
}

void removefd(int epollfd,int fd)
{
    epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,0);
    close(fd);
}

void modfd(int epollfd,int fd,int ev,bool lis)
{
    epoll_event event;
    event.data.fd=fd;
    if(lis)
        event.events=ev|EPOLLET|EPOLLONESHOT|EPOLLRDHUP;
    else
        event.events=EPOLLIN|EPOLLET|EPOLLRDHUP;
    epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&event);
}


void test(int sockfd)
{
    while (1)
    {
        char readle[63356];
        memset(readle,0,63356);
        int ret=recv(sockfd, readle, 63356, 0);
        //printf("\n-%s-\n",readle);
        if (ret==-1)
        {
            if (errno==EAGAIN||errno==EWOULDBLOCK)
                break;
        }
        else if (ret==0)
            break;
    }
    write(sockfd,httphead,strlen(httphead));
}

int main(int argc, char* argv[])
{
    if(argc<=2)
        printf("usage:%s ip_address port_number\n",basename(argv[0]));
    const char* ip=argv[1];
    int port=atoi(argv[2]);

    int ret=0;
    struct sockaddr_in address;
    bzero(&address,sizeof(address));
    address.sin_family=AF_INET;
    inet_pton(AF_INET,ip,&address.sin_addr);
    address.sin_port=htons(port);


    epoll_event events[10000];
    epollfd=epoll_create(10);
    
    th = new threadpool(1, 10000);
    th->start();

    for(int i = 0; i<1000; i++)
    {
        int connectfd=socket(PF_INET,SOCK_STREAM,0);
        assert(connectfd>=0);
        int ret = connect(connectfd,(struct sockaddr*)&address,sizeof(address));
        if(ret==0)
        {
            addfd(epollfd,connectfd,false);
            write(connectfd,httphead,strlen(httphead));
            printf("-%d-\n", i);
            struct linger tmp={1,0};
            setsockopt(connectfd,SOL_SOCKET,SO_LINGER,&tmp,sizeof(tmp));
        }
    }
    long sl = 0;
    while(true)
    {
        int number=epoll_wait(epollfd,events,20000,-1);
        if((number<0)&&(errno!=EINTR))
        {
            printf("epoll failure\n");
            break;
        }

        for(int i=0;i<number;i++)
        {
            int sockfd=events[i].data.fd;
            if(events[i].events&EPOLLIN)
            {
                //printf("连接数：12000 请求数：%ld\n", sl++);
                th->add(std::bind(&test, sockfd));
            }
            else if(events[i].events&(EPOLLRDHUP|EPOLLHUP|EPOLLERR))
                close(sockfd);
        }
    }
    close(epollfd);
    delete(th);
    return 0;
}